<script setup lang="ts">
import { ref, reactive, TransitionGroup } from 'vue'
import { NScrollbar, NTab, NTabs, NIcon, NButton, NSpace, NForm, NFormItem, NRadioButton, NDivider, NSlider, NModal, NDynamicInput, NInput, NInputNumber, NRadioGroup, NRadio, NCheckboxGroup, NCheckbox, NSelect, NDatePicker, NTimePicker } from 'naive-ui'
import type { FormRules, FormItemRule } from 'naive-ui'
import { CopyOutlined, CloseOutlined } from '@vicons/antd'
import type { FormComponent, DesignFormComponent } from '../model'
import { useFlowStore } from '../flowStore'

import FormViewer from '../form-viewer/index.vue'

const flowStore = useFlowStore()

const styleComponentList = reactive<FormComponent[]>([{
    componentCode: "Divider",
    componentName: "分割线",
    componentType: "Divider",
    componentSpan: 24,
    componentRequired: "0",
    componentTitlePlacement: "left",
    componentLineDashed: "0"
}])

const basicComponentList = reactive<FormComponent[]>([{
    componentCode: "Input",
    componentName: "单行文本输入",
    componentType: "Input",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "TextArea",
    componentName: "多行文本输入",
    componentType: "TextArea",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "Number",
    componentName: "数字输入",
    componentType: "Number",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "Radio",
    componentName: "单选组",
    componentType: "Radio",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "CheckBox",
    componentName: "多选组",
    componentType: "CheckBox",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "Select",
    componentName: "下拉单选",
    componentType: "Select",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "MultiSelect",
    componentName: "下拉多选",
    componentType: "MultiSelect",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "Date",
    componentName: "日期选择",
    componentType: "Date",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "DateRange",
    componentName: "日期区间选择",
    componentType: "DateRange",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "DateTime",
    componentName: "日期时间选择",
    componentType: "DateTime",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "DateTimeRange",
    componentName: "日期时间区间选择",
    componentType: "DateTimeRange",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "Time",
    componentName: "时间选择",
    componentType: "Time",
    componentSpan: 24,
    componentRequired: "0"
}])

const extComponentList = reactive<FormComponent[]>([{
    componentCode: "UserSelect",
    componentName: "人员选择",
    componentType: "userselect",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "DepartmentSelect",
    componentName: "部门选择",
    componentType: "DepartmentSelect",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "AreaSelect",
    componentName: "省市县选择",
    componentType: "AreaSelect",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "Image",
    componentName: "上传图片",
    componentType: "Image",
    componentSpan: 24,
    componentRequired: "0"
}, {
    componentCode: "Attachment",
    componentName: "上传附件",
    componentType: "Attachment",
    componentSpan: 24,
    componentRequired: "0"
}])

let flag = true
let selfFlag = true
let selectedComponent: { index: number, childIndex: number, component: FormComponent } = {
    index: -1,
    childIndex: -1,
    component: {
        componentCode: "",
        componentName: "",
        componentType: "",
        componentSpan: 24,
        componentRequired: "0"
    }
}
const selectedComponentId = ref<string>("")
const propertiesTab = ref<string>("表单属性")

const formPropertiesRules: FormRules = ({
    xGap: {
        type: "number",
        required: true,
        message: '请输入横向间距',
        trigger: ['input']
    },
    labelWidth: {
        type: "number",
        required: true,
        message: '请输入标题宽度',
        trigger: ['input']
    },
    labelPlacement: {
        required: true,
        message: '请输入标题位置',
        trigger: ['input']
    },
    requireMarkPlacement: {
        required: true,
        message: '请输入必填星号位置',
        trigger: ['input']
    }
})

const componentPropertiesRules: FormRules = ({
    componentCode: {
        required: true,
        trigger: ['input'],
        validator: (rule: FormItemRule, value: string): boolean | Error => {
            if (value) {
                let count = 0
                for (let i = 0; i < flowStore.formComponentList.length; i++) {
                    if (value === flowStore.formComponentList[i].componentCode) {
                        count++
                    }
                }
                if (count > 1) {
                    return new Error("组件编码已存在，请重新输入")
                }
            } else {
                return new Error("请输入组件编码")
            }
            return true
        }
    },
    componentName: {
        required: true,
        message: '请输入组件名称',
        trigger: ['input']
    },
})

const previewVisiable = ref<boolean>(false)

let lastChangeTime = 0

function generateComponentCode(component: FormComponent) {
    let count = 0
    for (let i = 0; i < flowStore.formComponentList.length; i++) {
        if (flowStore.formComponentList[i].componentType === component.componentType) {
            count++
        }
    }
    if (count === 0) {
        return component.componentCode
    } else {
        return component.componentType + count
    }
}

function createDragStart(component: FormComponent) {
    flag = true
    selectedComponent = {
        index: -1,
        childIndex: -1,
        component: { ...component, }
    }
    selectedComponent.component.componentCode = generateComponentCode(component)
}

function componentDragStart(index: number, component: DesignFormComponent) {
    component.isDragging = true
    component.isSelected = false
    selectedComponent.index = index
    selectedComponent.component = component
    selfFlag = true
}

function componentLibDragEnter() {
    if (flag === false) {
        flag = true
        flowStore.formComponentList.splice(selectedComponent.index, 1)
        selectedComponent.index = -1
    }
}

function formDragEnter() {
    if (flag) {
        flag = false
        selectedComponent.index = flowStore.formComponentList.length
        flowStore.formComponentList.push({
            ...selectedComponent.component,
            componentId: selectedComponent.component.componentCode,
            isDragging: false,
            isSelected: false
        })
    }
}

function componentDragEnter(index: number, component: FormComponent) {
    flag = false
    if (selectedComponent.index === -1) {
        flowStore.formComponentList.splice(index, 0, {
            ...selectedComponent.component,
            componentId: selectedComponent.component.componentCode,
            isDragging: true,
            isSelected: false
        })
        selectedComponent.index = index
    }
    if (selfFlag) {
        if (selectedComponent.index !== index) {
            flowStore.formComponentList.splice(selectedComponent.index, 1)
            flowStore.formComponentList.splice(index, 0, {
                ...selectedComponent.component,
                componentId: selectedComponent.component.componentCode,
                isDragging: true,
                isSelected: false
            })
            selectedComponent.index = index
            selfFlag = false
            lastChangeTime = Date.now()
        }
    }
    if (Date.now() - lastChangeTime >= 300 && component.componentCode === selectedComponent.component.componentCode) {
        selfFlag = true
    }
}

function componentDragEnd() {
    for (let i = 0; i < flowStore.formComponentList.length; i++) {
        flowStore.formComponentList[i].isDragging = false
    }
    selectedComponent = {
        index: -1,
        childIndex: -1,
        component: {
            componentCode: "",
            componentName: "",
            componentType: "",
            componentSpan: 24,
            componentRequired: "0"
        }
    }
}

function copyComponent(index: number, component: FormComponent) {
    const newComponent = { ...component }
    newComponent.componentCode = generateComponentCode(component)
    flowStore.formComponentList.splice(index, 0, {
        ...newComponent,
        componentId: newComponent.componentCode,
        isDragging: false,
        isSelected: false
    })
}

function deleteComponent(index: number, component: FormComponent) {
    flowStore.formComponentList.splice(index, 1)
}

function selectComponent(index: number, event: PointerEvent) {
    event.stopPropagation()
    for (let i = 0; i < flowStore.formComponentList.length; i++) {
        if (i === index) {
            flowStore.formComponentList[index].isSelected = !flowStore.formComponentList[index].isSelected
            if (flowStore.formComponentList[index].isSelected) {
                selectedComponentId.value = flowStore.formComponentList[index].componentId
                propertiesTab.value = "组件属性"
            }
        } else {
            flowStore.formComponentList[i].isSelected = false
        }
        flowStore.formComponentList[i].isDragging = false
    }
}
</script>

<template>
    <div class="flame-container"
        style="margin:0;background-color: var(--flame-container-color);transition: background-color .3s var(--n-bezier);">
        <div style="position:relative;width: 300px;height: 100%;border-right: 1px solid rgb(239, 239, 245);"
            @dragenter="componentLibDragEnter()" @dragend="componentDragEnd()">
            <div style="position: relative;height:40px;">
                <n-tabs type="segment">
                    <n-tab name="组件库" />
                </n-tabs>
            </div>
            <div style="position: absolute;top: 40px;left: 0;right: 0;bottom: 0;">
                <n-scrollbar trigger="none" style="max-height: 100%">
                    <div style="padding:0 12px;">
                        <div class="component-list-title">
                            样式组件
                        </div>
                        <div class="component-list">
                            <div v-for="component in styleComponentList" :key="component.componentCode" class="component"
                                draggable="true" @dragstart="createDragStart(component)" @dragend="componentDragEnd()">
                                {{ component.componentName }}
                            </div>
                        </div>
                    </div>
                    <div style="padding:0 12px;">
                        <div class="component-list-title">
                            基础组件
                        </div>
                        <div class="component-list">
                            <div v-for="component in basicComponentList" :key="component.componentCode" class="component"
                                draggable="true" @dragstart="createDragStart(component)" @dragend="componentDragEnd()">
                                {{ component.componentName }}
                            </div>
                        </div>
                    </div>
                    <div style="padding:0 12px;">
                        <div class="component-list-title">
                            扩展组件(TODO)
                        </div>
                        <div class="component-list">
                            <div v-for="component in extComponentList" :key="component.componentCode" class="component"
                                draggable="true" @dragstart="createDragStart(component)" @dragend="componentDragEnd()">
                                {{ component.componentName }}
                            </div>
                        </div>
                    </div>
                </n-scrollbar>
            </div>
        </div>
        <div style="position:relative;flex: 1;">
            <div class="form-container-header">
                <n-space style="float:right;">
                    <n-button type="primary" size="small" @click="flowStore.formComponentList.length = 0">清空</n-button>
                    <n-button type="primary" size="small" @click="previewVisiable = true">预览</n-button>
                </n-space>
            </div>
            <div style="position: absolute;top: 40px;left: 0;right: 0;bottom: 0;" @dragenter="formDragEnter">
                <n-scrollbar trigger="none" style="max-height: 100%">
                    <n-form :label-placement="flowStore.getLabelPlacement" :label-align="flowStore.getLabelAlign"
                        :label-width="flowStore.formProperties.labelWidth"
                        :require-mark-placement="flowStore.formProperties.requireMarkPlacement" disabled>
                        <transition-group name="form" tag="div" class="grad-form"
                            :style="{ gap: '0px ' + flowStore.formProperties.xGap + 'px' }">
                            <n-form-item v-for="(component, index) in flowStore.formComponentList"
                                :key="component.componentId"
                                :label="['Divider'].includes(component.componentType) ? '' : component.componentName"
                                :style="{ gridColumn: 'span ' + component.componentSpan + '/ span ' + component.componentSpan }"
                                :show-feedback="false" :show-require-mark="component.componentRequired === '1'"
                                :class="['component-wrapper', { 'dragging': component.isDragging }, { 'selected': component.isSelected }]"
                                @click="selectComponent(index, $event)" draggable="true"
                                @dragstart="componentDragStart(index, component)"
                                @dragenter="componentDragEnter(index, component)" @dragend="componentDragEnd()">

                                <n-divider v-if="component.componentType === 'Divider'"
                                    :dashed="component.componentLineDashed === '1'"
                                    :title-placement="component.componentTitlePlacement" style="margin:0">
                                    {{ component.componentName }}
                                </n-divider>

                                <n-input v-if="component.componentType === 'Input'" type="text"
                                    :placeholder="component.componentPlaceholder ? component.componentPlaceholder : '请输入内容'"
                                    clearable />

                                <n-input v-if="component.componentType === 'TextArea'" type="textarea"
                                    :placeholder="component.componentPlaceholder ? component.componentPlaceholder : '请输入内容'"
                                    clearable />

                                <n-input-number v-if="component.componentType === 'Number'"
                                    :placeholder="component.componentPlaceholder ? component.componentPlaceholder : '请输入数字'"
                                    clearable />

                                <n-radio-group v-if="component.componentType === 'Radio'">
                                    <n-space>
                                        <n-radio v-for="option in component.componentOptions" :key="option" :label="option"
                                            :value="option" />
                                        <n-radio v-if="!component.componentOptions" label="北京" value="北京" />
                                        <n-radio v-if="!component.componentOptions" label="上海" value="上海" />
                                        <n-radio v-if="!component.componentOptions" label="广州" value="广州" />
                                        <n-radio v-if="!component.componentOptions" label="深圳" value="深圳" />
                                    </n-space>
                                </n-radio-group>

                                <n-checkbox-group v-if="component.componentType === 'CheckBox'">
                                    <n-space>
                                        <n-checkbox v-for="option in component.componentOptions" :key="option"
                                            :label="option" :value="option" />
                                        <n-checkbox v-if="!component.componentOptions" label="北京" value="北京" />
                                        <n-checkbox v-if="!component.componentOptions" label="上海" value="上海" />
                                        <n-checkbox v-if="!component.componentOptions" label="广州" value="广州" />
                                        <n-checkbox v-if="!component.componentOptions" label="深圳" value="深圳" />
                                    </n-space>
                                </n-checkbox-group>

                                <n-select v-if="component.componentType === 'Select'" :options="component.componentOptions?.map((item) => {
                                    return { label: item, value: item }
                                })"
                                    :placeholder="component.componentPlaceholder ? component.componentPlaceholder : '请选择'"
                                    clearable />

                                <n-select v-if="component.componentType === 'MultiSelect'" multiple :options="component.componentOptions?.map((item) => {
                                    return { label: item, value: item }
                                })"
                                    :placeholder="component.componentPlaceholder ? component.componentPlaceholder : '请选择'"
                                    clearable />

                                <n-date-picker v-if="component.componentType === 'Date'" type="date"
                                    :placeholder="component.componentPlaceholder ? component.componentPlaceholder : '请选择日期'"
                                    clearable />

                                <n-date-picker v-if="component.componentType === 'DateRange'" type="daterange" clearable />

                                <n-date-picker v-if="component.componentType === 'DateTime'" type="datetime"
                                    :placeholder="component.componentPlaceholder ? component.componentPlaceholder : '请选择日期时间'"
                                    clearable />

                                <n-date-picker v-if="component.componentType === 'DateTimeRange'" type="datetimerange"
                                    clearable />

                                <n-time-picker v-if="component.componentType === 'Time'"
                                    :placeholder="component.componentPlaceholder ? component.componentPlaceholder : '请选择时间'"
                                    clearable />

                                <n-space :class="flowStore.getLabelPlacement === 'top' ? 'top-btn' : 'left-btn'">
                                    <n-button @click="copyComponent(index, component)" size="small" quaternary circle>
                                        <template #icon>
                                            <n-icon>
                                                <copy-outlined />
                                            </n-icon>
                                        </template>
                                    </n-button>
                                    <n-button @click="deleteComponent(index, component)" size="small" quaternary circle>
                                        <template #icon>
                                            <n-icon>
                                                <close-outlined />
                                            </n-icon>
                                        </template>
                                    </n-button>
                                </n-space>
                            </n-form-item>
                        </transition-group>
                    </n-form>
                </n-scrollbar>
            </div>
        </div>
        <div style="position:relative;width: 300px;height: 100%;border-left: 1px solid rgb(239, 239, 245);">
            <div style="position: relative;height:40px;">
                <n-tabs type="segment" v-model:value="propertiesTab">
                    <n-tab name="表单属性" />
                    <n-tab name="组件属性" />
                </n-tabs>
            </div>
            <div style="position: absolute;top: 40px;left: 0;right: 0;bottom: 0;">
                <n-scrollbar trigger="none" style="max-height: 100%">
                    <div v-if="propertiesTab === '表单属性'" style="padding:12px;">
                        <n-form :model="flowStore.formProperties" :rules="formPropertiesRules">
                            <n-form-item label="横向间距" path="xGap">
                                <n-input-number v-model:value="flowStore.formProperties.xGap" :min="0" clearable />
                            </n-form-item>
                            <n-form-item label="标题宽度" path="labelWidth">
                                <n-input-number v-model:value="flowStore.formProperties.labelWidth" :min="0" clearable />
                            </n-form-item>
                            <n-form-item label="标题位置" path="labelPlacement">
                                <n-radio-group v-model:value="flowStore.formProperties.labelPlacement">
                                    <n-radio-button value="0" label="顶部" />
                                    <n-radio-button value="1" label="左对齐" />
                                    <n-radio-button value="2" label="右对齐" />
                                </n-radio-group>
                            </n-form-item>
                            <n-form-item label="必填星号位置" path="requireMarkPlacement">
                                <n-radio-group v-model:value="flowStore.formProperties.requireMarkPlacement">
                                    <n-radio-button value="left" label="左侧" />
                                    <n-radio-button value="right" label="右侧" />
                                </n-radio-group>
                            </n-form-item>
                        </n-form>
                    </div>
                    <div v-if="propertiesTab === '组件属性'" style="padding:12px;">
                        <div v-for="component in flowStore.formComponentList" :key="component.componentId">
                            <n-form v-if="component.componentId === selectedComponentId" :model="component"
                                :rules="componentPropertiesRules">
                                <n-form-item v-if="component.componentType !== 'Divider'" label="组件编码" path="componentCode">
                                    <n-input v-model:value="component.componentCode" placeholder="请输入组件编码" />
                                </n-form-item>
                                <n-form-item label="组件名称" path="componentName">
                                    <n-input v-model:value="component.componentName" placeholder="请输入组件编码" />
                                </n-form-item>
                                <n-form-item
                                    v-if="['Input', 'TextArea', 'Number', 'Select', 'MultiSelect', 'Date', 'DateTime', 'Time'].includes(component.componentType)"
                                    label="提示内容">
                                    <n-input v-model:value="component.componentPlaceholder" placeholder="请输入提示内容" />
                                </n-form-item>
                                <n-form-item v-if="component.componentType !== 'Divider'" label="是否必填">
                                    <n-radio-group v-model:value="component.componentRequired">
                                        <n-space>
                                            <n-radio value="0" label="否" />
                                            <n-radio value="1" label="是" />
                                        </n-space>
                                    </n-radio-group>
                                </n-form-item>
                                <n-form-item v-if="component.componentType === 'Divider'" label="标题位置">
                                    <n-radio-group v-model:value="component.componentTitlePlacement">
                                        <n-radio-button value="left" label="左" />
                                        <n-radio-button value="center" label="中" />
                                        <n-radio-button value="right" label="右" />
                                    </n-radio-group>
                                </n-form-item>
                                <n-form-item v-if="component.componentType === 'Divider'" label="线条样式">
                                    <n-radio-group v-model:value="component.componentLineDashed">
                                        <n-radio-button value="0" label="实线" />
                                        <n-radio-button value="1" label="虚线" />
                                    </n-radio-group>
                                </n-form-item>
                                <n-form-item label="栅格宽度">
                                    <n-slider v-model:value="component.componentSpan" :max="24" :min="4"
                                        :marks="{ 4: '4', 6: '6', 12: '12', 24: '24' }" step="mark" />
                                </n-form-item>
                                <n-form-item
                                    v-if="['Radio', 'CheckBox', 'Select', 'MultiSelect'].includes(component.componentType)"
                                    label="选项设置">
                                    <n-dynamic-input v-model:value="component.componentOptions" placeholder="请输入选项" />
                                </n-form-item>
                            </n-form>
                        </div>
                    </div>
                </n-scrollbar>
            </div>
        </div>
    </div>
    <n-modal v-model:show="previewVisiable">
        <form-viewer @cancel="previewVisiable = false" @temp-submit="previewVisiable = false" @submit="previewVisiable = false"/>
    </n-modal>
</template>

<style scoped>
.component-list-title {
    width: 100%;
    height: 40px;
    line-height: 40px;
    padding-left: 3px;
}

.component-list {
    display: grid;
    grid-template-columns: repeat(2, 132px);
    justify-content: space-between;
    grid-auto-rows: 55px;
}

.component-list .component {
    background-color: #fff;
    height: 40px;
    line-height: 40px;
    padding-left: 7px;
    cursor: grab;
    border: 1px solid #e0e0e0;
    border-radius: 3px;
}

.component-list .component:hover {
    border: 1px solid var(--flame-primary-color);
    color: var(--flame-primary-color);
}

.form-container-header {
    position: relative;
    height: 38px;
    line-height: 38px;
    padding: 0 6px;
    background-color: rgb(247, 247, 250);
    box-shadow: 0 0px 0px 0 rgb(3 27 78 / 6%);
    border-bottom: 1px solid rgb(239, 239, 245);
}

.grad-form {
    width: 100%;
    display: grid;
    grid-template-columns: repeat(24, minmax(0px, 1fr));
}

.form-move {
    transition: transform .3s;
}

.component-wrapper {
    margin-top: 13px;
    padding: 12px;
    border: 1px solid rgb(239, 239, 245);
    cursor: grab;
}

.dragging {
    border: 1px solid var(--flame-primary-color);
}

.selected {
    border-top: 1px solid var(--flame-primary-color);
    border-left: 5px solid var(--flame-primary-color);
    border-right: 1px solid var(--flame-primary-color);
    border-bottom: 1px solid var(--flame-primary-color);
}

.top-btn {
    position: absolute;
    top: -39px;
    right: -4px;
}

.left-btn {
    position: absolute;
    top: -26px;
    right: -4px;
}
</style>